/*
    单片机接收数据，双指针循环解析函数，
    数据协议：
head len_H len_L    sum_a    cmd data[1...n] sum_b tail
                  (head+len)  
 50    00    07       57      01  01 02       B2    DF
可能需要升级固件，每包数据长度会超过255，所以长度需要两字节
e.g.  
50 00 07 57 01 01 02 B2 DF
50 00 07 57 02 00 02 B2 DF
50 00 07 57 02 01 02 B3 DF
50 00 06 56 03 00 AF DF
50 00 06 56 03 01 B0 DF
*/


#include "dataProcess.h"
#include "usart.h"

#include "stdio.h"

#define VERSION_FIRMWARE   "V1.6-20240510"
/*
V1.6-20240510 解耦完毕，DataPreprocess函数根据入参选择源数据，响应函数等，不再依赖固定数组，可对多个数据源分别解析，只需初始配置以及实现响应函数
目前测试为每隔100ms发送一个9字节的数据包，连续发送了10万包数据，无一丢包错包
show all dbgcnt info
Get Cmd 10 : 30478
Get Cmd 20 : 30474
Get Cmd 21 : 30473
Get Cmd 30 : 6
Cnt of STATE1 : 25895
Cnt of STATE2_OK : 25895
Cnt of STATE2_ERR : 0
Cnt of STATE3_OK : 25895
Cnt of STATE3_ERR : 0


V1.5-20240510 解决了存在丢包的问题，目前测试为每隔100ms发送9字节，连续发送了33000包数据，无一丢包错包，同时写出解耦相关功能代码，待验证
V1.4-20240509 统一dbg计数，增加状态机的打印信息
*/


void DataCopy(uint8_t *dst,ID_DATA_e id,uint16_t iStart,uint16_t len)
{
    for (i = 0; i < rxDcb[id].dataLen; i++)
    {
        dst[i]=DATA(id,iStart+i);
    }
}

/*
DataHandle中不能使用原始的memcpy，只能使用DataCopy，因为涉及到循环读写
*/
void DataHandle_U5()
{
    // uint16_t i;
	// printf("DataHandle_U5 %d data:\r\n",rxDcb[ID_U5].dataLen);
    // for (i = 0; i < rxDcb[ID_U5].dataLen; i++)
    // {
	//     printf("%02x\r\n",DATA(ID_U5,i));
    // }
 	switch (DATA(ID_U5,4))
    {
    case 0x01:
        DBG_INC(CMD10);
        break;
    case 0x02:
        if(0==DATA(ID_U5,5))
        {
            DBG_INC(CMD20);
        }
        else if(1==DATA(ID_U5,5))
        {
            DBG_INC(CMD21);
        }
        break;
    case 0x03:
        DBG_INC(CMD30);
        if(0==DATA(ID_U5,5))
        {
            DbgCntShowAll();
        }
        else if(1==DATA(ID_U5,5))
        {
            DbgCntClearAll();
        }
        break;
    
    default:
        break;
    }
}

uint8_t gBuf2[3]={
	3,2,3
};
void DataHandle_U4()
{
	printf("DataHandle_U4 %d\r\n",DATA(ID_U4,0));
}

RxDcb_t rxDcb[ID_MAX]={
	{Rx5RecData,0,RX5_SIZE,0,0,0,DataHandle_U5},
	{gBuf2,0,3,0,0,0,DataHandle_U4}
};




/*
    DBG_CNT相关
*/
uint16_t cnt_dbg[CNT_MAX]={0};

char *gDbgCntName[CNT_MAX]={
    "Get Cmd 10",
    "Get Cmd 20",
    "Get Cmd 21",
    "Get Cmd 30",
    "Cnt of STATE1",
    "Cnt of STATE2_OK",
    "Cnt of STATE2_ERR",
    "Cnt of STATE3_OK",
    "Cnt of STATE3_ERR",
};
void DbgCntShowAll()
{
    printf("show all dbgcnt info\r\n");
    for(DBG_CNT_e i=CMD10;i<CNT_MAX;i++)
    {
        printf("%s : %d\r\n",gDbgCntName[i],cnt_dbg[i]);
    }
}

void DbgCntClearAll()
{
    DBG_CNT_e i=CMD10;
    printf("clear all dbgcnt info\r\n");
    for(i=CMD10;i<CNT_MAX;i++)
    {
        cnt_dbg[i]=0;
    }
    for(i=CMD10;i<CNT_MAX;i++)
    {
        printf("%s : %d\r\n",gDbgCntName[i],cnt_dbg[i]);
    }
}


uint8_t IsIntervalEnough(ID_DATA_e id,uint16_t interval)
{
	uint16_t tmp=0;
    uint16_t iRx=rxDcb[id].iRxRawBuf;
	if(iRx>rxDcb[id].iRead)
	{
		tmp=iRx-rxDcb[id].iRead;
	}
	else
	{
		tmp=iRx+rxDcb[id].sizeRawBuf-rxDcb[id].iRead;
	}
	if(tmp>interval)
	{
		return 1;
	}
    else
    {
        return 0;
    }
}

void DataProcess()
{
    for(ID_DATA_e id=ID_U5;id<ID_MAX;id++)
    {
        DataPreprocess(id);
    }    
}

void DataPreprocess(ID_DATA_e id)
{
    uint8_t sum_tmp=0;
    uint16_t i=0;
   if (rxDcb[id].iRead!=rxDcb[id].iRxRawBuf)
   {
       switch (rxDcb[id].status)
       {
       case STA_WAIT_HEAD://第一状态，初次进入，等待包头
           if(DATA_HEAD == DATA(id,0))
           {
               DBG_INC(STATE1);
               rxDcb[id].status=STA_WAIT_SUMA;
           }
           else
           {
                rxDcb[id].iRead=(rxDcb[id].iRead+1)%rxDcb[id].sizeRawBuf;
           }
           break;
       case STA_WAIT_SUMA://第二状态，等待第一次和校验，若此校验和通过，证明包头和长度有效，进入第三状态，否则返回第一状态
           if(IsIntervalEnough(id,3))// 
           {
                sum_tmp=0;
                for (i = 0; i < 3; i++)//此处3为固定值，包头1个字节，长度两个字节，
                {
                    sum_tmp+=DATA(id,i);
                }
               if(DATA(id,3)==sum_tmp)
               {
                    rxDcb[id].dataLen=(DATA(id,1)<<8)+DATA(id,2);
                   rxDcb[id].status=STA_WAIT_TAIL;
                    DBG_INC(STATE2_OK);
               }
               else
               {
                    DBG_INC(STATE2_ERR);
                     printf("STA_WAIT_SUMA ERR iread=%d sum %02x buf:",rxDcb[id].iRead,sum_tmp);
                    for (i = 0; i < rxDcb[id].sizeRawBuf; i++)//此处3为固定值，包头1个字节，长度两个字节，
                    {
                        printf(" %02x",rxDcb[id].pRawBuf[i]);
                    }
                    printf("\r\n");
                   rxDcb[id].iRead=(rxDcb[id].iRead+1)%rxDcb[id].sizeRawBuf;
                   rxDcb[id].status=STA_WAIT_HEAD;
               }
           }
           break;
       case STA_WAIT_TAIL://第三状态，根据长度取完所有数据，并进行第二次和校验，校验包尾，若校验通过，进入后续指令响应代码， 否则返回第一状态
           if(IsIntervalEnough(id,1+rxDcb[id].dataLen))
           {
                sum_tmp=0;
                for (i = 0; i < rxDcb[id].dataLen; i++)//此处3为固定值，包头1个字节，长度两个字节，
                {
                    sum_tmp+=DATA(id,i);
                }
                if((DATA(id,rxDcb[id].dataLen)==sum_tmp)&&(DATA_TAIL==DATA(id,rxDcb[id].dataLen+1)))//check sum   check tail
                {
                    //处理命令
                    //DataHandle(&rxDcb[id].pRawBuf[rxDcb[id].iRead],rxDcb[id].dataLen);
                    DBG_INC(STATE3_OK);
                    //CmdHandle(0,rxDcb[id].iRead,rxDcb[id].dataLen);//第一个参数，在函数内部去选择
                    if (NULL!=rxDcb[id].pFun)
                    {
                        rxDcb[id].pFun();
                    }
                    
                    rxDcb[id].iRead=(rxDcb[id].iRead+2+rxDcb[id].dataLen)%rxDcb[id].sizeRawBuf;
                }
                else
                {
                    DBG_INC(STATE3_ERR);
                     printf("STA_WAIT_TAIL ERR iread=%d sum %02x buf:",rxDcb[id].iRead,sum_tmp);
                    for (i = 0; i < rxDcb[id].sizeRawBuf; i++)//此处3为固定值，包头1个字节，长度两个字节，
                    {
                        printf(" %02x",rxDcb[id].pRawBuf[i]);
                    }
                    printf("\r\n");
                    rxDcb[id].iRead=(rxDcb[id].iRead+1)%rxDcb[id].sizeRawBuf;
                }
               rxDcb[id].status=STA_WAIT_HEAD;
           }
           break;
       
       default:
           break;
       }
       
   }    
}








// void CmdHandle(uint8_t index,uint16_t iRead,uint16_t len)
// {
//     if (0==index)//表示从uart5的接收数组中拿数据
//     {
//         switch (DATA(4))
//         {
//         case 0x01:
//             //UartSend(0x10);
//                     //printf("get cmd 01\r\n");
//             DBG_INC(CMD10);
//             break;
//         case 0x02:
//             if(0==DATA(5))
//             {
//                             //printf("get cmd 02  00\r\n");
//                 //UartSend(0x20);
//                 DBG_INC(CMD20);
//             }
//             else if(1==DATA(5))
//             {
//                             //printf("get cmd 02  01\r\n");
//                 //UartSend(0x21);
//                 DBG_INC(CMD21);
//             }
//             break;
//         case 0x03:
//             DBG_INC(CMD30);
//             if(0==DATA(5))
//             {
//                 DbgCntShowAll();
//             }
//             else if(1==DATA(5))
//             {
//                 DbgCntClearAll();
//             }
//             break;
        
//         default:
//             break;
//         }
//     }
    
// }


// uint8_t IsIntervalEnough(uint16_t interval)
// {
//     uint16_t lastpoint_rx=0;
// 	uint16_t tmp=0;
//     lastpoint_rx=Rx5Point;
// 	if(lastpoint_rx>rxDcb.iRead)
// 	{
// 		tmp=lastpoint_rx-rxDcb.iRead;
// 	}
// 	else
// 	{
// 		tmp=lastpoint_rx+RX5_SIZE-rxDcb.iRead;
// 	}
// 	if(tmp>interval)
// 	{
// 		return 1;
// 	}
// 	else
// 	{
// 		return 0;
// 	}
// }
/*
针对某一个固定的协议，对接收buf里的数据做预处理，遍历buf处理其中所有符合协议的数据包，然后清0读写索引
*/
//双指针循环解析，解决溢出风险,但会丢包
// void DataPreprocess()
// {
//     uint8_t sum_tmp=0;
//     uint16_t i=0;
//    if (rxDcb.iRead!=Rx5Point)
//    {
//         rxDcb.tickLastGet=HAL_GetTick();
//        switch (rxDcb.status)
//        {
//        case STA_WAIT_HEAD://第一状态，初次进入，等待包头
//            if(DATA_HEAD == DATA(0))
//            {
//                DBG_INC(STATE1);
//                rxDcb.status=STA_WAIT_SUMA;
//            }
//            else
//            {
//                 rxDcb.iRead=(rxDcb.iRead+1)%RX5_SIZE;
//            }
//            break;
//        case STA_WAIT_SUMA://第二状态，等待第一次和校验，若此校验和通过，证明包头和长度有效，进入第三状态，否则返回第一状态
//            if(IsIntervalEnough(3))// 
//            {
//                 sum_tmp=0;
//                 for (i = 0; i < 3; i++)//此处3为固定值，包头1个字节，长度两个字节，
//                 {
//                     sum_tmp+=DATA(i);
//                 }
//                if(DATA(3)==sum_tmp)
//                {
//                     rxDcb.dataLen=(DATA(1)<<8)+DATA(2);
//                    rxDcb.status=STA_WAIT_TAIL;
//                     DBG_INC(STATE2_OK);
//                }
//                else
//                {
//                     DBG_INC(STATE2_ERR);
//                      printf("STA_WAIT_SUMA ERR iread=%d sum %02x buf:",rxDcb.iRead,sum_tmp);
//                     for (i = 0; i < RX5_SIZE; i++)//此处3为固定值，包头1个字节，长度两个字节，
//                     {
//                         printf(" %02x",Rx5RecData[i]);
//                     }
//                     printf("\r\n");
//                    rxDcb.iRead=(rxDcb.iRead+1)%RX5_SIZE;
//                    rxDcb.status=STA_WAIT_HEAD;
//                }
//            }
//            break;
//        case STA_WAIT_TAIL://第三状态，根据长度取完所有数据，并进行第二次和校验，校验包尾，若校验通过，进入后续指令响应代码， 否则返回第一状态
//            if(IsIntervalEnough(1+rxDcb.dataLen))
//            {
//                 sum_tmp=0;
//                 for (i = 0; i < rxDcb.dataLen; i++)//此处3为固定值，包头1个字节，长度两个字节，
//                 {
//                     sum_tmp+=DATA(i);
//                 }
//                 if((DATA(rxDcb.dataLen)==sum_tmp)&&(DATA_TAIL==DATA(rxDcb.dataLen+1)))//check sum   check tail
//                 {
//                     //处理命令
//                     //DataHandle(&Rx5RecData[rxDcb.iRead],rxDcb.dataLen);
//                     DBG_INC(STATE3_OK);
//                     CmdHandle(0,rxDcb.iRead,rxDcb.dataLen);//第一个参数，在函数内部去选择
//                     rxDcb.iRead=(rxDcb.iRead+2+rxDcb.dataLen)%RX5_SIZE;
//                 }
//                 else
//                 {
//                     DBG_INC(STATE3_ERR);
//                      printf("STA_WAIT_TAIL ERR iread=%dlast_rxpoint=%d sum %02x buf:",rxDcb.iRead,lastpoint_rx,sum_tmp);
//                     for (i = 0; i < RX5_SIZE; i++)//此处3为固定值，包头1个字节，长度两个字节，
//                     {
//                         printf(" %02x",Rx5RecData[i]);
//                     }
//                     printf("\r\n");
//                     rxDcb.iRead=(rxDcb.iRead+1)%RX5_SIZE;
//                 }
//                rxDcb.status=STA_WAIT_HEAD;
//            }
//            break;
       
//        default:
//            break;
//        }
       
//    }
// }
